package edu.iscas.appcheckclient.util;


import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.sql.Timestamp;

import edu.iscas.appcheckclient.model.actions.Action;
import edu.iscas.appcheckclient.model.actions.Check;
import edu.iscas.appcheckclient.model.actions.Comment;
import edu.iscas.appcheckclient.model.actions.MockedHttpResponse;
import edu.iscas.appcheckclient.model.actions.MockedIntent;
import edu.iscas.appcheckclient.model.actions.MockedLocation;
import edu.iscas.appcheckclient.model.actions.Perform;
import edu.iscas.appcheckclient.model.actions.Press;
import edu.iscas.appcheckclient.model.actions.Screenshot;

public class GsonUtil {

    public static final class ActionDeserializeAdapter implements JsonDeserializer<Action>{
        @Override
        public Action deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            String nameValue = json.getAsJsonObject().get("name").getAsString();
            if (nameValue.equals("assert")) {
                return (Action) GsonUtil.buildGson().fromJson(json, Check.class);
            }
            if (nameValue.equals("comment")) {
                return (Action) GsonUtil.buildGson().fromJson(json, Comment.class);
            }
            if (nameValue.equals("perform")) {
                return (Action) GsonUtil.buildGson().fromJson(json, Perform.class);
            }
            if (nameValue.equals("press")) {
                return (Action) GsonUtil.buildGson().fromJson(json, Press.class);
            }
            if (nameValue.equals("screenshot")) {
                return (Action) GsonUtil.buildGson().fromJson(json, Screenshot.class);
            }
            if (nameValue.equals("mockedintent")){
                return (Action) GsonUtil.buildGson().fromJson(json, MockedIntent.class);
            }
            if (nameValue.equals("mockedlocation")){
                return (Action) GsonUtil.buildGson().fromJson(json, MockedLocation.class);
            }
            if (nameValue.equals("mockedhttpresponse")){
                return (Action) GsonUtil.buildGson().fromJson(json, MockedHttpResponse.class);
            }

            throw new JsonParseException("Unknown action name: " + typeOfT);
        }
    }

    public static final class ActionSerializeAdapter implements JsonSerializer<Action>{
        @Override
        public JsonElement serialize(Action src, Type typeOfSrc, JsonSerializationContext context) {
            if(src instanceof Check){
                return GsonUtil.buildGson().toJsonTree(src, Check.class);
            }
            if(src instanceof Comment){
                return GsonUtil.buildGson().toJsonTree(src, Comment.class);
            }
            if(src instanceof Perform){
                return GsonUtil.buildGson().toJsonTree(src, Perform.class);
            }
            if(src instanceof Press){
                return GsonUtil.buildGson().toJsonTree(src, Press.class);
            }
            if(src instanceof Screenshot){
                return GsonUtil.buildGson().toJsonTree(src, Screenshot.class);
            }
            if(src instanceof MockedIntent){
                return GsonUtil.buildGson().toJsonTree(src, MockedIntent.class);
            }
            if(src instanceof MockedLocation){
                return GsonUtil.buildGson().toJsonTree(src, MockedLocation.class);
            }
            if(src instanceof MockedHttpResponse){
                return GsonUtil.buildGson().toJsonTree(src, MockedHttpResponse.class);
            }
            throw new JsonParseException("Unknown action type: " + src.getClass().toString());
        }
    }

    public static final class TimestampSerializeAdapter implements JsonSerializer<Timestamp>{
        @Override
        public JsonElement serialize(Timestamp src, Type typeOfSrc, JsonSerializationContext context) {
            return context.serialize(Long.valueOf(src.getTime()));
        }
    }

    public static final class TimestampDeserializeAdapter implements JsonDeserializer<Timestamp>{
        @Override
        public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            return new Timestamp(json.getAsLong());
        }
    }
    public static Gson buildGson(){
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(Action.class, new ActionDeserializeAdapter());
        gsonBuilder.registerTypeAdapter(Action.class, new ActionSerializeAdapter());
        gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampSerializeAdapter());
        gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampDeserializeAdapter());
        return gsonBuilder.create();
    }
}
